package com.sfac.springboot.modules.common.controller;

import com.sfac.springboot.modules.common.entity.ExceptionLog;
import com.sfac.springboot.modules.common.service.ExceptionLogService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;


 /*捕获控制器错有异常并进行处理*/
@ControllerAdvice
public class ExceptionController {

    public final static Logger LOGGER = LoggerFactory.getLogger(ExceptionController.class);
    @Autowired
    private ExceptionLogService exceptionLogService;

/**
     * 处理控制层所有的异常，根据 调用类型 和 异常类型 来决定返回对象
     * 接口调用异常，返回403,404,500 对应的json 数据
     * 页面调用异常，返回403,404,500 对应的错误页面*/


    @ExceptionHandler(value = Exception.class)//注解意思，不同的异常跳转不同的试图
    public ModelAndView handleException(HttpServletRequest request,
                                        Exception exception){
        //输出异常信息
        exception.printStackTrace();
        LOGGER.debug(exception.getMessage());

        //插入异常信息
        insertExceptionLog(request,exception);

        //根据异常类型，封装数据（状态码、消息、异常错误页面对应路径）
        int status = 200;
        String message = "";
        String data = "";

        // 暂将 ArithmeticException（算术异常） 作为没有权限处理
        if (exception instanceof ArithmeticException){
            status = 403;
            message = "没有权限";
            data = "/common/403";
        }else {
            status = 500;
            message = "内部错误";
            data = "/common/500";
        }

        //判断请求类型，接口调用则返回json数据，反之返回错误页面
        if(checkCallType(request)){
            ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
            mv.addObject("status",status);
            mv.addObject("message",message);
            mv.addObject("data",data);
            return mv;
        }else {
            return new ModelAndView(new RedirectView(data));//ModelAndView 可以传输值和也可以设置页面
        }
    }

    //判断请求控制器是接口还是页面
    private boolean checkCallType(HttpServletRequest request){
        HandlerMethod handlerMethod = (HandlerMethod) request.getAttribute(
                "org.springframework.web.servlet.HandlerMapping.bestMatchingHandler");
        //从方法上面获取ResponseBody注解
        ResponseBody[] annotations1 = handlerMethod.getMethod().getAnnotationsByType(ResponseBody.class);
        //从类上面获取ResponseBody 注解
        ResponseBody[] annotations2 = handlerMethod.getBeanType().getAnnotationsByType(ResponseBody.class);
        //从类上面获取 RestController 注解
        RestController[] annotations3 = handlerMethod.getBeanType().getAnnotationsByType(RestController.class);
        return(annotations1.length > 0) || (annotations2.length > 0) || (annotations3.length > 0);
    }

    //保存异常信息
    private void insertExceptionLog(HttpServletRequest request,
                                    Exception exception){
        ExceptionLog exceptionLog = new ExceptionLog();
        exceptionLog.setIp(request.getRemoteAddr());
        exceptionLog.setPath(request.getServletPath());

        HandlerMethod handlerMethod = (HandlerMethod) request.getAttribute(
                "org.springframework.web.servlet.HandlerMapping.bestMatchingHandler");

        exceptionLog.setClassName((handlerMethod.getBeanType().getName()));
        exceptionLog.setMethodName(handlerMethod.getMethod().getName());
        exceptionLog.setExceptionType(exception.getClass().getSimpleName());

        String message = exception.getMessage();
        int length = 0;
              if (StringUtils.isNotBlank(message)){
                  length = message.length() > 200 ? 200 :message.length();
              }
        exceptionLog.setExceptionMessage(StringUtils.isBlank(exception.getMessage())?
                exception.getMessage().substring(0,length):"");

        exceptionLogService.insertExceptionLog(exceptionLog);

    }


}
